package hbec.kettle.etl.common.util;

import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import hbec.kettle.etl.common.constants.Constants;
import hbec.kettle.etl.common.constants.DataBase;
import hbec.kettle.etl.common.exception.ExceptionTracker;

public class DbcpUtils {
	private static final Logger logger = LoggerFactory.getLogger(DbcpUtils.class);
	
	public final static Map<DataBase, DataSource> dataSources = new HashMap<>();
	public final static Map<String, Map<String, String>> dbUrls = new HashMap<>();
	
	static {
		Properties dbcpProperties = PropertiesUtils.getDbcpProperties();
		String dbs = dbcpProperties.getProperty("hbec.kettle.etl.dbs");
		
		if (dbs != null && !dbs.isEmpty()) {
			String[] dbnames = dbs.split(",");
			
			for (String dbname : dbnames) {
				DataSource ds = new DataSource();
				
				String db = dbname.trim();
				String username = dbcpProperties.getProperty(MessageFormat.format(Constants.USERNAME, db));
				String password = dbcpProperties.getProperty(MessageFormat.format(Constants.PASSWORD, db));
				String host = dbcpProperties.getProperty(MessageFormat.format(Constants.HOST, db));
				String port = dbcpProperties.getProperty(MessageFormat.format(Constants.PORT, db));
				String type = dbcpProperties.getProperty(MessageFormat.format(Constants.TYPE, db));
				String databasename = dbcpProperties.getProperty(MessageFormat.format(Constants.DATABASENAME, db));
				
				if(host == null || port == null 
						|| username == null || password == null) {
					username = dbcpProperties.getProperty(MessageFormat.format(Constants.USERNAME, DataBase.DB));
					password = dbcpProperties.getProperty(MessageFormat.format(Constants.PASSWORD, DataBase.DB));
					host = dbcpProperties.getProperty(MessageFormat.format(Constants.HOST, DataBase.DB));
					port = dbcpProperties.getProperty(MessageFormat.format(Constants.PORT, DataBase.DB));
					type = dbcpProperties.getProperty(MessageFormat.format(Constants.TYPE, DataBase.DB));
				}
				
				Map<String, String> dbUrl = new HashMap<>();
				dbUrl.put("IP", host);
				dbUrl.put("PORT", port);
				dbUrl.put("DATABASENAME", (databasename == null ? db : databasename));
				dbUrl.put("USER", username);
				dbUrl.put("PASSWORD", password);
				dbUrl.put("TYPE", type);
				dbUrls.put(db, dbUrl);
				
				type = (type == null || "".equals(type)) ? "mysql" : type;
				
				String driver = null;
				String url = null;
				if(host != null && port != null 
						&& username != null && password != null) {
					switch(type) {
						case "mysql":
							driver = Constants.MYSQL_DRIVER;
							url = MessageFormat.format("jdbc:mysql://{0}:{1}/{2}{3}", host, port, (databasename == null ? db : databasename), Constants.JDBC_PARAMETERS);
							break;
						case "sqlserver":
							driver = Constants.SQLSERVER_DRIVER;
							url = MessageFormat.format("jdbc:sqlserver://{0}:{1};databaseName={2}", host, port, (databasename == null ? db : databasename));
							break;
						case "oracle":
							driver = Constants.ORACLE_DRIVER;
							url = MessageFormat.format("jdbc:oracle:thin:@{0}:{1}:{2}", host, port, (databasename == null ? db : databasename));
							break;
						case "sqlite":
							driver = Constants.SQLITE_DRIVER;
							url = MessageFormat.format("jdbc:sqlite:{0}", (databasename == null ? db : databasename));
							break;
					}
					ds.setUsername(username);
					ds.setPassword(password);
					ds.setUrl(url);
					ds.setDriverClassName(driver);
					configDbcpFinally(dbcpProperties, ds, db);
					dataSources.put(DataBase.valueOf(db.toUpperCase()), ds);
				}
			}
		}
	}

	private static void configDbcpFinally(Properties dbcpProperties, DataSource ds, String db) {
		ds.setValidationQuery("SELECT 1");
		
		ds.setInitialSize(dbcpProperties.getProperty(MessageFormat.format(Constants.INITIALSIZE, db)) == null
				? 1 : Integer.parseInt(dbcpProperties.getProperty(MessageFormat.format(Constants.INITIALSIZE, db))));
		
		ds.setMinIdle(dbcpProperties.getProperty(MessageFormat.format(Constants.MINIDLE, db))==null
				? 2 : Integer.parseInt(dbcpProperties.getProperty(MessageFormat.format(Constants.MINIDLE, db))));
		
		ds.setMaxIdle(dbcpProperties.getProperty(MessageFormat.format(Constants.MAXIDLE, db))==null
				? 5 : Integer.parseInt(dbcpProperties.getProperty(MessageFormat.format(Constants.MAXIDLE, db))));
		
		ds.setMaxActive(dbcpProperties.getProperty(MessageFormat.format(Constants.MAXACTIVE, db))==null
				? 10 : Integer.parseInt(dbcpProperties.getProperty(MessageFormat.format(Constants.MAXACTIVE, db))));
		
		ds.setMaxWait(dbcpProperties.getProperty(MessageFormat.format(Constants.MAXWAIT, db))==null
				? 10 * 1000 : Integer.parseInt(dbcpProperties.getProperty(MessageFormat.format(Constants.MAXWAIT, db))));
		
		ds.setTestWhileIdle(true);
		ds.setTestOnBorrow(false);
		ds.setNumTestsPerEvictionRun(5);
		ds.setMinEvictableIdleTimeMillis(30 * 60 * 1000);
		ds.setTimeBetweenEvictionRunsMillis(30 * 1000);
		ds.setLogAbandoned(false);
		ds.setRemoveAbandoned(false);
		ds.setRemoveAbandonedTimeout(30000);
		
		try {
			ds.getConnection().close();
		} catch (SQLException e) {
			logger.error(ExceptionTracker.trace(e));
		}
	}	
}
